package _case

import (
	"fmt"
	"sync"
)

func MutexCase() {
	//singleRoutine()
	//multipleRoutine()
	//multipleSafeRoutine()
	multipleSafeRoutineByRWMutex()
}

// 单协程操作
func singleRoutine() {
	m := make(map[string]int)
	list := []string{"A", "B", "C", "D", "E", "F"}
	for i := 0; i < 20; i++ {
		for _, v := range list {
			if _, ok := m[v]; ok {
				m[v]++
			} else {
				m[v] = 1
			}
		}
	}
	fmt.Println(m)
}

// 多协程操作，非协程安全
// error：fatal error: concurrent map writes
func multipleRoutine() {
	m := make(map[string]int)
	list := []string{"A", "B", "C", "D", "E", "F"}
	wg := sync.WaitGroup{}
	for i := 0; i < 20; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for _, v := range list {
				if _, ok := m[v]; ok {
					m[v]++
				} else {
					m[v] = 1
				}
			}
		}()
	}
	wg.Wait()
	fmt.Println(m)
}

// 互斥锁，协程安全
func multipleSafeRoutine() {
	type MpMutex struct {
		data map[string]int
		sync.Mutex
	}

	m := MpMutex{make(map[string]int), sync.Mutex{}}

	list := []string{"A", "B", "C", "D", "E", "F"}
	wg := sync.WaitGroup{}
	for i := 0; i < 20; i++ {
		wg.Add(1)
		go func() {
			m.Mutex.Lock()
			defer m.Mutex.Unlock()
			defer wg.Done()
			for _, v := range list {
				if _, ok := m.data[v]; ok {
					m.data[v]++
				} else {
					m.data[v] = 1
				}
			}
		}()
	}
	wg.Wait()
	fmt.Println(m.data)
}

type cache struct {
	data    map[string]string
	RWMutex sync.RWMutex
}

func (c *cache) Get(key string) string {
	c.RWMutex.RLock()
	defer c.RWMutex.RUnlock()
	if v, ok := c.data[key]; ok {
		return v
	}
	return ""
}

func (c *cache) Set(key, value string) {
	c.RWMutex.Lock()
	defer c.RWMutex.Unlock()
	c.data[key] = value
}

func NewCache() *cache {
	return &cache{make(map[string]string), sync.RWMutex{}}
}

// 读写锁，协程安全
func multipleSafeRoutineByRWMutex() {
	c := NewCache()
	wg := sync.WaitGroup{}
	wg.Add(1)
	go func() {
		defer wg.Done()
		c.Set("name", "jc")
	}()

	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			fmt.Println(c.Get("name"))
		}()
	}
	wg.Wait()
}
